package com.baichuan;

import com.alibaba.fastjson.JSONObject;
import com.baichuan.entity.CmsRequestLog;
import com.baichuan.entity.sys.Log;
import com.baichuan.service.CmsRequestLogService;
import com.baichuan.util.IpAddressUtil;
import com.baichuan.util.RequestHeaderParams;
import com.baichuan.util.RequestParamsUtil;
import com.baichuan.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Auther: leo
 * @Date: 2021/9/20 20:16
 * @Description: AOP切面请求日志处理
 */
@Slf4j
@Aspect
@Component
public class RequestLogAspect {

    @Autowired
    private CmsRequestLogService logService;

    /**
     * 切入点:所有controller
     */
    @Pointcut("execution(* com.baichuan.controller..*(..))")//指定切点
    public void pointCutMethod() {
    }

    /**
     * 声明环绕通知
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Log log = new Log();

        long startTime = System.currentTimeMillis();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//获取请求对象
        String url = request.getRequestURI();
        String method = request.getMethod();//请求类型
        log.setHttpMethod(method);
        String args = "{}";//参数

        if (method.equals("GET")) {
            args = JSONObject.toJSONString(RequestParamsUtil.getRequestParams());
        } else if (!url.contains("/upload/file")) {//不是上传文件时获取参数
                if (pjp.getArgs() != null && pjp.getArgs().length > 0) {
                    List<Object> argsList = new ArrayList();
                    for (int i = 0; i < pjp.getArgs().length; i++) {
                        Object object = pjp.getArgs()[i];
                        if (object instanceof Serializable) {
                            argsList.add(object);
                        }
                    }
                    if (!argsList.isEmpty())
                        args = JSONObject.toJSONString(argsList);
                }

        }
        Class<?> targetCls=pjp.getTarget().getClass();//获取类的字节码对象，通过字节码对象获取方法信息
        MethodSignature ms=(MethodSignature)pjp.getSignature();//获取方法对象
        String httpMethod=targetCls.getName()+"."+ms.getName();//获取类名+获取方法名
        log.setClassMethod(httpMethod);

        RequestHeaderParams headerParams = RequestParamsUtil.getHeaderParams();//请求工具类
        Object ret = pjp.proceed();
        String result = ret == null ? null : ret.toString();
        int times = (int) (System.currentTimeMillis() - startTime);

        //Integer userId = RequestParamsUtil.getSysUserId();
        //if (userId != null)
        //    log.setUserId(userId + "");

        log.setIpAddress(IpAddressUtil.getIpAddress(request));
        if (StringUtils.isNotEmpty(args) && args.length() > 4000) {
            args = args.substring(0, 4000);
        }
        log.setUrl(url);
        //上传图片不记录上传参数
        log.setRequestParams(args);
        log.setTimeCost(times+0L);

        if (StringUtils.isNotEmpty(result) && result.length() > 4000) {
            result = result.substring(0, 4000);
        }
        log.setResponse(result);
        logService.addLog(log);
        return ret;
    }

    /**
     * 异常
     *
     * @param jp
     * @param ex
     */
    @AfterThrowing(value = "pointCutMethod()", throwing = "ex")
    public void afterThrowing(JoinPoint jp, Exception ex) {
        Log log = new Log();

        long startTime = System.currentTimeMillis();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String url = request.getRequestURI();
        String method = request.getMethod();
        log.setHttpMethod(method);
        String args = "{}";

        try {
            if (method.equals("GET")) {
                args = JSONObject.toJSONString(RequestParamsUtil.getRequestParams());
            } else if (!url.contains("/upload/file")) {
                    if (jp.getArgs() != null && jp.getArgs().length > 0) {
                        List<Object> argsList = new ArrayList();
                        for (int i = 0; i < jp.getArgs().length; i++) {
                            Object object = jp.getArgs()[i];
                            if (object instanceof Serializable) {
                                argsList.add(object);
                            }
                        }
                        if (!argsList.isEmpty())
                            args = JSONObject.toJSONString(argsList);
                    }
                }

        } catch (Exception e) {
            log.setException(e.toString());
        }
        Class<?> targetCls=jp.getTarget().getClass();//获取类的字节码对象，通过字节码对象获取方法信息
        MethodSignature ms=(MethodSignature)jp.getSignature();//获取方法对象
        String httpMethod=targetCls.getName()+"."+ms.getName();//获取类名+获取方法名
        log.setClassMethod(httpMethod);

        RequestHeaderParams headerParams = RequestParamsUtil.getHeaderParams();
        String result = getStackTrace(ex);
        int times = (int) (System.currentTimeMillis() - startTime);

        //Integer userId = RequestParamsUtil.getSysUserId();
        //if (userId != null)
        //    log.setUserId(userId + "");

        log.setIpAddress(IpAddressUtil.getIpAddress(request));
        if (StringUtils.isNotEmpty(args) && args.length() > 3000) {
            args = args.substring(0, 3000);
        }
        log.setUrl(url);
        //上传图片不记录上传参数
        log.setRequestParams(args);
        log.setTimeCost(times+0L);

        if (StringUtils.isNotEmpty(result) && result.length() > 3000) {
            result = result.substring(0, 3000);
        }
        log.setResponse(result);
        logService.addLog(log);
    }

    private String getStackTrace(Exception e) {
        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw, true));
        return sw.toString();
    }
}
